package sample;

import javax.swing.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {


    private Block[] blocks = new Block[30];

    private PageTable[] pageTables;
    private int[] pageClub;//内存物理块初始化为pagecNum
    //内存物理块总大小
    private int pagecNum;
    //每一个页面的大小
    private int blockNum;
    private int surplus;//记录剩余物理块数量
    //新建立的作业号(0~19)与大小
    private int pageNum, pageSize;
    private int voidornot;
    //系统可用物理块数
    private int num;
    //页表map
    private Map<Integer, Integer> pageTable;


    public String initProcessBlock() {
        for (int i = 0; i < pagecNum; i++) {//内存物理块的初始化
            this.pageClub[i] = 0;
        }
        this.num = this.pagecNum / this.blockNum;

        return " 内存物理块已经成功初始化！本系统共有" + this.num + "个可用物理块，每个块的大小为" + this.blockNum + "kb";

    }

    public void checksurplus()//检查可用空间
    {
        surplus = 0;
        for (int i = 0; i < pagecNum; i++) {
            if (pageClub[i] == 0) {
                surplus++;
            }
        }
    }

    public String showsurplus() {
        StringBuilder sb = new StringBuilder();
        sb.append("现在输出物理块的存储信息:\n");
        sb.append("※--------------------※\n");
        for (int i = 0; i < num; i++) {
            if ((i % 10) == 0) {
                sb.append("| ");
            }
            sb.append(pageClub[i]).append(" ");
            if ((i + 1) % 10 == 0) {
                sb.append("|\n");
            }
        }
        sb.append("※--------------------※\n");
        return sb.toString();
    }

    public String showPageTable(int pageNum) {

        StringBuilder sb = new StringBuilder();
        sb.append("现在输出作业").append(pageNum).append("的页表:\n");
        sb.append("| 页号 | 块号  |\n");

        int last = 0;

        for (int i = 0; ; i++, last++) {
            if (pageTables[pageNum].pageTableItem[i] == 88) {
                break;
            }
        }
        for (int i = 0; i < last; i++) {
            pageTable.put(i, pageTables[pageNum].pageTableItem[i]);
            sb.append("|  ").append(i).append("  |  ").append(pageTables[pageNum].pageTableItem[i]).append("   |\n");
        }

        sb.append("*------※------*\n");
        return sb.toString();
    }


    private String createWork1() {

        int danwei = pageSize / blockNum;
        checksurplus();//检查可用空间
        if (danwei > surplus) {
            return "空间不足";

        } else {
            for (int i = 0; i < 20; i++) {
                pageTables[pageNum].pageTableItem[i] = 88;//预用初始化
            }
            return "将为你分配" + danwei + "个物理块！";
        }

    }


    public String createWork(String anums) {


        String message = createWork1();
        if (!"空间不足".equals(message)) {


            int danwei = message.charAt(5) - '0';
            for (int i = 0; i < 20; i++) {
                pageTables[pageNum].pageTableItem[i] = 88;//预用初始化
            }

            System.out.println("将为你分配" + danwei + "个物理块！");
            System.out.println("请顺序输入对应存储的物理块号:");
            int yebnum = 0;
            String[] anumArr = anums.split(",");
            for (int i = 0; i < danwei; i++) {
                int anum = Integer.parseInt(anumArr[i]);
                if (pageClub[anum] == 0) {
                    pageClub[anum] = pageNum;
                    pageTables[pageNum].pageTableItem[yebnum] = anum;
                    yebnum++;
                } else {
                    return "该物理块已经被占用。请重新输入其它物理块号(T_T)";
                }
            }
            voidornot = 1;
            pageTables[pageNum].flag = 1;
            return showsurplus() + " " + showPageTable(pageNum);
        } else {
            return "";
        }

    }


    int check() {
        if (voidornot == 0) {
            return 1;
        } else {
            return 0;
        }
    }


    private String fifo(int win, String nums, int X) {
        StringBuilder sb = new StringBuilder();
        String[] numArr = nums.split(",");
        if (pageTables[win].flag == 0) {
            return "没有你这个儿子进程！";
        } else {
            int last = 0;
            for (int i = 0; ; i++, last++) {
                if (pageTables[win].pageTableItem[i] == 88) {
                    break;
                }
            }

            System.out.println("pageTables[win].pageTableItem = " + Arrays.toString(pageTables[win].pageTableItem));
            System.out.println("请输入15个由作业" + win + "的物理块号所组成的序列:");

            for (int i = 0; i < last; i++) {
                System.out.print(pageTables[win].pageTableItem[i]);
                if (i != (last - 1)) {
                    System.out.print("、");
                } else {
                    System.out.println();
                }
            }
            int[] number = new int[15];
            for (int i = 0; i < 15; i++) {
                number[i] = Integer.parseInt(numArr[i]);
            }
            int error = 0;

            for (int i = 0; i < 30; i++) {
                blocks[i].num = 88;
            }
            for (int i = 0; i < 15; i++) {
                int flag1 = 0;
                for (int j = 0; j < X; j++) {
                    if (number[i] == blocks[j].num) {
                        System.out.println(number[i]);
                        sb.append(number[i]).append("\n");
                        flag1 = 1;
                    }
                }
                if (flag1 == 0) {
                    error++;
                    //cout<<"error="<<error<<endl;
                    if (error <= X)//未满
                    {
                        blocks[error - 1].num = number[i];
                        System.out.print(number[i] + "|");
                        sb.append(number[i]).append("|");
                        for (int k = 0; k < i + 1; k++) {
                            if (blocks[k].num != 88) {
                                sb.append(blocks[k].num).append(" ");
                            }
                        }
                        sb.append("\n");
                    } else //已经满，要置换
                    {
                        blocks[(error - 1) % X].num = number[i];
                        System.out.print(number[i] + "|");
                        sb.append(number[i]).append("|");
                        for (int k = 0; k < X; k++) {
                            if (blocks[k].num != 88) {
                                System.out.print(blocks[k].num + " ");
                                sb.append(blocks[k].num).append(" ");
                            }
                        }
                        sb.append("\n");
                    }
                }
            }
            sb.append("使用FIFO算法在分配的物理块为").append(X).append("个情况下，缺页次数是").append(error).append("次。命中率为").append((1 - ((double) error / 15)) * 10).append("%!\n");
            System.out.println("error = " + error);
            System.out.println("FIFO:" + sb.toString());
            return sb.toString();
        }
    }

    private String lru(int win, String nums, int X) {
        StringBuilder sb = new StringBuilder();
        String[] numArr = nums.split(",");
        if (pageTables[win].flag == 0) {
            return "没有你这个儿子";
        } else {
            int last = 0, flag3 = 0;
            for (int i = 0; ; i++, last++) {
                if (pageTables[win].pageTableItem[i] == 88) {
                    break;
                }
            }
            for (int i = 0; i < last; i++) {
                sb.append(pageTables[win].pageTableItem[i]);
                if (!(i == (last - 1))) {
                    sb.append("、");
                } else {
                    sb.append("\n");
                }
            }
            int[] number = new int[15];
            for (int i = 0; i < 15; i++) {
                number[i] = Integer.parseInt(numArr[i]);
            }
            int error = 0;

            int flag2 = 1;
            int topnumber = 0;

            for (int i = 0; i < 30; i++)//物理块初始化
            {
                blocks[i].num = 88;
            }
            for (int i = 0; i < 15; i++) {
                int flag4 = 0;
                for (int o = 0; o < X; o++)//查询栈中是否存在要访问的页面
                {
                    if (number[i] == blocks[o].num)//如果访问的页面在栈中
                    {
                        //int flag4=0;
                        if (number[i - 1] != number[i]) {
                            for (int p = o; p < topnumber; p++) //栈元素向后推，将最近访问的页号存到栈顶元素。
                            {
                                blocks[p].num = blocks[p + 1].num;
                            }
                            blocks[topnumber - 1].num = number[i];
                        }

                        sb.append(number[i]).append("|");
                        for (int j = 0; j < 10; j++) {
                            if (blocks[j].num != 88) {
                                sb.append(blocks[j].num).append(" ");
                            }
                        }
                        //cout<<"top"<<topnumber;
                        sb.append("\n");
                        flag4 = 1;
                        break;
                    }
                }
                if (flag4 == 0)//缺页
                {

                    //cout<<topnumber<<endl;
                    error++;
                    if (flag3 == 0) {
                        if (topnumber < X)//如果此时栈未满
                        {
                            topnumber++;
                            blocks[topnumber - 1].num = number[i];
                        } else if (topnumber == X)//此时栈已经满了
                        {
                            //topnumber=X-1;
                            flag3 = 1;//表示满了
                        }
                    }
                    if (flag3 != 0) //栈满了，首先将栈顶以下的都向下移，再将新的页面放到栈顶,topnumber=X
                    {
                        for (int m = 0; m < X - 1; m++) {
                            blocks[m].num = blocks[m + 1].num;
                        }
                        blocks[X - 1].num = number[i];
                    }
                    sb.append(number[i]).append("|");
                    for (int k = 0; k < 10; k++) {
                        if (blocks[k].num != 88) {
                            sb.append(blocks[k].num).append(" ");
                        }
                    }
                    //cout<<"top"<<topnumber;

                    sb.append("缺页(T_T)");
                    sb.append("\n");
                }

            }
            sb.append("使用LRU算法在分配的物理块为").append(X).append("个情况下，缺页次数是").append(error).append("次。命中率为").append((1 - ((double) error / 15)) * 100).append("%!\n");
            return sb.toString();
        }
    }


    private JFrame frame1;
    private JFrame frame2;
    private JFrame frame3;
    private JFrame frame4;


    public void addCompoentToFrame1(JPanel panel) {
        panel.setLayout(null);
        JLabel pageFrame = new JLabel("设置总内存块大小");
        pageFrame.setBounds(0, 20, 220, 25);
        panel.add(pageFrame);
        JTextField pageFrameText = new JTextField(20);
        pageFrameText.setBounds(100, 20, 165, 25);
        panel.add(pageFrameText);
        JLabel pageSize = new JLabel("设置页面大小");
        pageSize.setBounds(10, 50, 200, 25);
        panel.add(pageSize);

        JTextField pageSizeText = new JTextField(20);
        pageSizeText.setBounds(100, 50, 165, 25);
        panel.add(pageSizeText);

        JButton ok = new JButton("确认");
        JButton writeWorkButton = new JButton("建立页表");
        JButton disPlaceButton = new JButton("置换算法");
        JButton addressButton = new JButton("地址转换");
        ok.setBounds(10, 80, 160, 25);
        writeWorkButton.setBounds(200, 80, 100, 25);
        disPlaceButton.setBounds(290, 80, 100, 25);
        addressButton.setBounds(380, 80, 100, 25);


        JTextPane textMessage = new JTextPane();
        textMessage.setBounds(0, 150, 500, 500);
        panel.add(textMessage);
        panel.add(ok);
        panel.add(writeWorkButton);
        panel.add(disPlaceButton);
        panel.add(addressButton);
        ok.addActionListener(e -> {
            String pagecNum = pageFrameText.getText();
            String blockNum = pageSizeText.getText();
            if (isNumeric(pagecNum) && isNumeric(blockNum)) {
                this.pagecNum = Integer.parseInt(pagecNum);
                this.blockNum = Integer.parseInt(blockNum);
                String result = initProcessBlock();
                System.out.println(result);
                textMessage.setText(result);
                writeWorkButton.addActionListener(e1 -> {
                    makeFrame2Visible();
                });
                disPlaceButton.addActionListener(e1 -> {
                    makeFrame3Visible();
                });

                addressButton.addActionListener(e1 -> {
                    makeFrame4Visible();
                });


            } else {
                JPanel jPanel = new JPanel();
                JOptionPane.showMessageDialog(jPanel, "输入错误，请重新输入", "标题", JOptionPane.WARNING_MESSAGE);
            }
        });

    }

    public boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        return isNum.matches();
    }


    public Main() {
        this.pageClub = new int[2000];
        this.pagecNum = 50;
        this.blockNum = 1;
        this.voidornot = 0;
        this.num = 0;
        this.pageTables = new PageTable[20];
        for (int i = 0; i < 20; i++) {
            this.pageTables[i] = new PageTable();
        }
        for (int i = 0; i < 30; i++) {
            this.blocks[i] = new Block();
        }
        this.pageTable = new HashMap<>(20);
    }

    private void addCompoentToFrame2(JPanel panel) {
        panel.setLayout(null);

        JLabel pageNumLabel = new JLabel("输入新建立的作业号(0~19)");
        pageNumLabel.setBounds(10, 20, 200, 25);
        panel.add(pageNumLabel);
        JTextField pageNumText = new JTextField(20);
        pageNumText.setBounds(200, 20, 200, 25);
        panel.add(pageNumText);

        JLabel pageSizeLabel = new JLabel("设置页面大小（单位：KB）");
        pageSizeLabel.setBounds(10, 50, 200, 25);
        panel.add(pageSizeLabel);
        JTextField pageSizeText = new JTextField(20);
        pageSizeText.setBounds(200, 50, 200, 25);
        panel.add(pageSizeText);


        JTextPane textMessage = new JTextPane();
        textMessage.setBounds(0, 150, 500, 500);
        panel.add(textMessage);
        JButton okButton1 = new JButton("确认提交作业号与页面大小");
        okButton1.setBounds(200, 80, 200, 25);
        panel.add(okButton1);
        okButton1.addActionListener(e -> {
            String pageNum = pageNumText.getText();
            String pageSize = pageSizeText.getText();
            if (isNumeric(pageNum) && isNumeric(pageSize)) {
                this.pageNum = Integer.parseInt(pageNum);
                this.pageSize = Integer.parseInt(pageSize);


                String message = createWork1();
                textMessage.setText(message);
                if (!"空间不足".equals(message)) {

                    pageSizeText.setVisible(false);
                    okButton1.setVisible(false);
                    pageNumLabel.setVisible(false);
                    pageSizeLabel.setVisible(false);
                    pageNumText.setVisible(false);
                    JLabel label = new JLabel("请顺序输入对应存储的物理块号");
                    label.setBounds(10, 20, 160, 25);
                    panel.add(label);
                    JTextField pageBlockText = new JTextField();
                    pageBlockText.setBounds(10, 100, 165, 25);
                    panel.add(pageBlockText);

                    JButton okButton2 = new JButton("提交");
                    okButton2.setBounds(200, 80, 160, 25);
                    panel.add(okButton2);
                    okButton2.addActionListener(e1 -> {
                        String anums = pageBlockText.getText();
                        textMessage.setText(createWork(anums));

                    });

                }

            }
        });


    }

    private void addCompoentToFrame3(JPanel panel) {
        panel.setLayout(null);
        JButton fifoButton = new JButton("FIFO");
        JButton lruButton = new JButton("LRU");
        JTextPane textMessage = new JTextPane();
        textMessage.setBounds(0, 0, 700, 350);
        panel.add(textMessage);
        fifoButton.setBounds(0, 350, 350, 50);
        lruButton.setBounds(250, 350, 350, 50);
        panel.add(lruButton);
        panel.add(fifoButton);
        lruButton.addActionListener(e -> {


            System.out.println("LRU");
            JTextField winText = new JTextField(20);
            winText.setText("设置要跑的进程");
            winText.setBounds(10, 420, 200, 25);
            panel.add(winText);


            JTextField pageListText = new JTextField(20);
            pageListText.setText("输入15个由作业5的物理块号所组成的序列");
            pageListText.setBounds(10, 460, 200, 25);
            panel.add(pageListText);


            JTextField blockText = new JTextField(20);
            blockText.setText("分配物理块数");
            blockText.setBounds(10, 500, 200, 25);
            panel.add(blockText);

            JButton button = new JButton("运行");
            button.setBounds(10, 540, 200, 25);
            panel.add(button);
            button.addActionListener(e1 -> {
                int win = Integer.parseInt(winText.getText());
                String nums = pageListText.getText();
                int X = Integer.parseInt(blockText.getText());
                String message = lru(win, nums, X);
                textMessage.setText(message);
            });

        });
        fifoButton.addActionListener(e -> {
            JTextField winText = new JTextField();
            winText.setText("设置要跑的进程");
            winText.setBounds(10, 420, 200, 25);
            panel.add(winText);


            JTextField pageListText = new JTextField();
            pageListText.setText("输入15个由作业5的物理块号所组成的序列");
            pageListText.setBounds(10, 460, 200, 25);
            panel.add(pageListText);


            JTextField blockText = new JTextField();
            blockText.setText("分配物理块数");
            blockText.setBounds(10, 500, 200, 25);
            panel.add(blockText);

            JButton button = new JButton("运行");
            button.setBounds(10, 540, 200, 25);
            panel.add(button);


            button.addActionListener(e1 -> {
                int win = Integer.parseInt(winText.getText());
                String nums = pageListText.getText();
                int X = Integer.parseInt(blockText.getText());
                String message = fifo(win, nums, X);
                textMessage.setText(message);
            });

        });

    }

    private void addCompoentToFrame4(JPanel panel) {
        panel.setLayout(null);
        JLabel label = new JLabel("逻辑地址");
        label.setBounds(0, 0, 60, 40);
        JTextField addressText = new JTextField();
        addressText.setBounds(70, 0, 100, 40);
        JButton button = new JButton("转换");
        button.setBounds(0, 70, 100, 40);
        panel.add(label);
        panel.add(addressText);
        panel.add(button);
        button.addActionListener(e -> {
            int address = Integer.parseInt(addressText.getText());
            int blockNumByte = blockNum * 1024;
            int currentPageNum = address / blockNumByte;
            int inPageOffset = address % blockNumByte;
            int pageFrameNum = pageTable.get(currentPageNum);
            int localAddress = pageFrameNum * blockNumByte + inPageOffset;
            JPanel jPanel = new JPanel();
            JOptionPane.showMessageDialog(jPanel, "物理地址为:" + localAddress, "物理地址", JOptionPane.INFORMATION_MESSAGE);
        });


    }

    private void makeFrame4Visible() {

        JPanel panel = new JPanel();
        addCompoentToFrame4(panel);
        frame3 = new JFrame("置换算法");

        // 添加面板
        frame3.add(panel);
        frame3.setSize(700, 700);
        frame3.setLocation(500, 0);
        frame3.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame3.setVisible(true);
    }

    private void makeFrame3Visible() {

        JPanel panel = new JPanel();
        addCompoentToFrame3(panel);
        frame3 = new JFrame("置换算法");

        // 添加面板
        frame3.add(panel);
        frame3.setSize(700, 700);
        frame3.setLocation(500, 0);
        frame3.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame3.setVisible(true);
    }

    private void makeFrame2Visible() {
        frame2 = new JFrame("分配空间，建立页表");
        frame2.setSize(500, 500);
        frame2.setLocation(500, 0);
        frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        JPanel panel = new JPanel();
        // 添加面板
        frame2.add(panel);
        addCompoentToFrame2(panel);
        frame2.setVisible(true);
    }

    private void makeFrame1Visible() {
        // 创建 JFrame 实例
        frame1 = new JFrame("首页");
        // Setting the width and height of frame
        frame1.setSize(500, 500);
        frame1.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        /* 创建面板，这个类似于 HTML 的 div 标签
         * 我们可以创建多个面板并在 JFrame 中指定位置
         * 面板中我们可以添加文本字段，按钮及其他组件。
         */
        JPanel panel = new JPanel();
        // 添加面板
        frame1.add(panel);
        /*
         * 调用用户定义的方法并添加组件到面板
         */


        addCompoentToFrame1(panel);
        // 设置界面可见
        frame1.setVisible(true);
    }


    public static void main(String[] args) {
        Main main = new Main();
        main.makeFrame1Visible();
    }
}
